package com.sokal.easycare.common.utils.FastDFS;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

import javax.imageio.ImageIO;

import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.IOUtils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient1;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.alibaba.simpleimage.ImageRender;
import com.alibaba.simpleimage.SimpleImageException;
import com.alibaba.simpleimage.render.ReadRender;
import com.alibaba.simpleimage.render.ScaleParameter;
import com.alibaba.simpleimage.render.ScaleRender;
import com.alibaba.simpleimage.render.WriteRender;

/**
 * FastDFS分布式文件系统操作
 * 
 * @author liliangdong
 *
 */
public class FastDFSClient {

	private static final String CONF_FILENAME = Thread.currentThread().getContextClassLoader()
			.getResource("fdfs_client.conf").getPath();

	private static StorageClient1 storageClient = null;

	private static Logger logger = LoggerFactory.getLogger(FastDFSClient.class);

	/**
	 * 只加载一次.
	 */
	static {
		try {
			logger.info("=== CONF_FILENAME:" + CONF_FILENAME);
			ClientGlobal.init(CONF_FILENAME);
			TrackerClient trackerClient = new TrackerClient(ClientGlobal.g_tracker_group);
			TrackerServer trackerServer = trackerClient.getConnection();
			if (trackerServer == null) {
				logger.error("getConnection return null");
			}
			StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
			if (storageServer == null) {
				logger.error("getStoreStorage return null");
			}
			storageClient = new StorageClient1(trackerServer, storageServer);
		} catch (Exception e) {
			logger.error(e.toString());
			e.printStackTrace();
		}
	}

	/**
	 * 
	 * @param file
	 *            文件
	 * @param fileName
	 *            文件名
	 * @return 返回Null则为失败
	 */
	public static String uploadFile(File file, String fileName) throws Exception {
		FileInputStream fis = null;
		try {
			NameValuePair[] meta_list = null; // new NameValuePair[0];
			//判断文件是否为图片
		    if (ImageIO.read(file) == null) {  
				fis = new FileInputStream(file);
		    } else{
				//如果是图片需要进行压缩处理
				fis = new FileInputStream(imageScale(new FileInputStream(file), fileName));
		    }
			byte[] file_buff = null;
			if (fis != null) {
				int len = fis.available();
				file_buff = new byte[len];
				fis.read(file_buff);
			}

			String fileid = storageClient.upload_file1(file_buff, getFileExt(fileName), meta_list);
			logger.info(fileid);
			return fileid;
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					logger.error(e.toString());
					throw e;
				}
			}
		}
	}

	/**
	 * 
	 * @param file
	 *            文件
	 * @param fileName
	 *            文件名
	 * @return 返回Null则为失败
	 */
	public static String uploadFile(MultipartFile multipartFile, String fileName) throws Exception {
		FileInputStream fis = null;
		try {
			NameValuePair[] meta_list = null; // new NameValuePair[0];
			//判断文件是否为图片
		    if (ImageIO.read((FileInputStream)multipartFile.getInputStream()) == null)  {  
				fis = (FileInputStream)multipartFile.getInputStream();
		    } else{
				//如果是图片需要进行压缩处理
				fis = new FileInputStream(imageScale((FileInputStream)multipartFile.getInputStream(), fileName));
		    }
			byte[] file_buff = null;
			if (fis != null) {
				int len = fis.available();
				file_buff = new byte[len];
				fis.read(file_buff);
			}

			String fileid = storageClient.upload_file1(file_buff, getFileExt(fileName), meta_list);
			logger.info(fileid);
			return fileid;
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					logger.error(e.toString());
					throw e;
				}
			}
		}
//		CommonsMultipartFile cf = (CommonsMultipartFile) multipartFile;
		// 这个myfile是MultipartFile的
//		DiskFileItem fi = (DiskFileItem) cf.getFileItem();
//		File file = fi.getStoreLocation();
//		return uploadFile(file, fileName);
		/*
		 * FileInputStream fis = null; try { NameValuePair[] meta_list = null;
		 * // new NameValuePair[0]; byte[] file_buff = file.getBytes();
		 * 
		 * String fileid = storageClient.upload_file1(file_buff,
		 * getFileExt(fileName), meta_list); return fileid; } finally { if (fis
		 * != null) { try { fis.close(); } catch (IOException e) {
		 * logger.error(e.toString()); throw (e); } } }
		 */
	}

	/**
	 * 根据组名和远程文件名来删除一个文件
	 * 
	 * @param groupName
	 *            例如 "group1" 如果不指定该值，默认为group1
	 * @param fileName
	 *            例如"M00/00/00/wKgxgk5HbLvfP86RAAAAChd9X1Y736.jpg"
	 * @return 0为成功，非0为失败，具体为错误代码
	 */
	public static int deleteFile(String groupName, String fileName) {
		try {
			int result = storageClient.delete_file(groupName == null ? "group1" : groupName, fileName);
			return result;
		} catch (Exception ex) {
			logger.error(ex.toString());
			return 0;
		}
	}

	/**
	 * 根据fileId来删除一个文件（我们现在用的就是这样的方式，上传文件时直接将fileId保存在了数据库中）
	 * 
	 * @param fileId
	 *            file_id源码中的解释file_id the file id(including group name and
	 *            filename);例如
	 *            group1/M00/00/00/ooYBAFM6MpmAHM91AAAEgdpiRC0012.xml
	 * @return 0为成功，非0为失败，具体为错误代码
	 */
	public static int deleteFile(String fileId) {
		try {
			int result = storageClient.delete_file1(fileId);
			return result;
		} catch (Exception ex) {
			logger.error(ex.toString());
			return 0;
		}
	}

	/**
	 * 修改一个已经存在的文件
	 * 
	 * @param oldFileId
	 *            原来旧文件的fileId, file_id源码中的解释file_id the file id(including group
	 *            name and filename);例如
	 *            group1/M00/00/00/ooYBAFM6MpmAHM91AAAEgdpiRC0012.xml
	 * @param file
	 *            新文件
	 * @param filePath
	 *            新文件路径
	 * @return 返回空则为失败
	 */
	public static String modifyFile(String oldFileId, File file, String filePath) {
		String fileid = null;
		try {
			// 先上传
			fileid = uploadFile(file, filePath);
			if (fileid == null) {
				return null;
			}
			// 再删除
			int delResult = deleteFile(oldFileId);
			if (delResult != 0) {
				return null;
			}
		} catch (Exception ex) {
			logger.error(ex.toString());
			ex.printStackTrace();
			return null;
		}
		return fileid;
	}

	/**
	 * 文件下载
	 * 
	 * @param fileId
	 * @return 返回一个流
	 */
	public static InputStream downloadFile(String fileId) {
		try {
			byte[] bytes = storageClient.download_file1(fileId);
			InputStream inputStream = new ByteArrayInputStream(bytes);
			return inputStream;
		} catch (Exception ex) {
			logger.error(ex.toString());
			ex.printStackTrace();
			return null;
		}
	}

	/**
	 * 获取文件后缀名（不带点）.
	 * 
	 * @return 如："jpg" or "".
	 */
	private static String getFileExt(String fileName) {
		if (StringUtils.isEmpty(fileName) || !fileName.contains(".")) {
			return "";
		} else {
			return fileName.substring(fileName.lastIndexOf(".") + 1); // 不带最后的点
		}
	}

	/**
	 * 文件压缩
	 * @param in
	 * @param fileName
	 * @return
	 */
	private static File imageScale(FileInputStream inStream, String fileName) {
		// 原图片
		File out = new File(System.getProperty("java.io.tmpdir") + UUID.randomUUID().toString().replaceAll("-", "") + "."
				+ getFileExt(fileName));
		ScaleParameter scaleParam = new ScaleParameter(750, 750); // 将图像缩略到750x750以内，不足750x750则不做任何处理

		//FileInputStream inStream = null;
		FileOutputStream outStream = null;
		WriteRender wr = null;
		try {
			//inStream = new FileInputStream(in);
			outStream = new FileOutputStream(out);
			ImageRender rr = new ReadRender(inStream);
			ImageRender sr = new ScaleRender(rr, scaleParam);
			wr = new WriteRender(sr, outStream);

			wr.render(); // 触发图像处理
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			IOUtils.closeQuietly(inStream); // 图片文件输入输出流必须记得关闭
			IOUtils.closeQuietly(outStream);
			if (wr != null) {
				try {
					wr.dispose(); // 释放simpleImage的内部资源
				} catch (SimpleImageException ignore) {
					ignore.printStackTrace();
				}
			}
		}
		return out;
	}
}
